﻿using System.Collections.Generic;
using Microsoft.Xna.Framework;

namespace PoolGame2.Managers
{
    public delegate void EntryHandler();
    public delegate void ExitHandler();
    public delegate void UpdateHandler(GameTime gameTime);
    public delegate void DrawHandler(GameTime gameTime);
    public delegate void TransitionCallback(int iOldState, int iNewState);

    public class StateMachineState
    {
        public int iState;
        public EntryHandler onEnter;
        public ExitHandler onExit;
        public UpdateHandler onUpdate;
        public DrawHandler onDraw;

        public StateMachineState(int iStateID, EntryHandler enter, ExitHandler exit, UpdateHandler update, DrawHandler draw)
        {
            iState = iStateID;
            onEnter = enter;
            onExit = exit;
            onUpdate = update;
            onDraw = draw;
        }
    }

    public class StateMachine
    {
        private List<StateMachineState> stateList = new List<StateMachineState>();
        public List<StateMachineState> STATES
        {
            get { return stateList; }
        }

        private int iCurrentState = -1;
        public int STATE
        {
            get { return iCurrentState; }
        }

        private int iPreviousState = -1;
        public int PREVIOUS_STATE
        {
            get { return iPreviousState; }
        }

        private bool bInTransition = false;
        public bool TRANSITIONING
        {
            get { return bInTransition; }
        }

        private float fTransitionTime = 0.0f;
        public float TRANSITION_TIME
        {
            get { return fTransitionTime; }
            set { fTransitionTime = value; }
        }

        private TransitionCallback onTransition;
        public TransitionCallback OnTransition
        {
            set { onTransition = value; }
        }

        public StateMachine(TransitionCallback callback)
        {
            onTransition = callback;
        }

        public void Transition(int state)
        {
            iPreviousState = iCurrentState;
            iCurrentState = state;
            fTransitionTime = 0.0f;
            bInTransition = false;

            StateLeave(iPreviousState);

            if (fTransitionTime > 0.0f)
                bInTransition = true;
            else
            {
                bInTransition = false;
                StateEnter(iCurrentState);
            }
        }

        public StateMachineState GetCurrentState()
        {
            foreach (StateMachineState mstate in stateList)
            {
                if (mstate.iState == iCurrentState)
                    return mstate;
            }
            return null;
        }

        public void Update(GameTime time)
        {
            if (bInTransition)
            {
                fTransitionTime -= (float)(time.ElapsedGameTime.TotalSeconds);
                if (fTransitionTime <= 0.0f)
                {
                    bInTransition = false;
                    fTransitionTime = 0.0f;
                    StateEnter(iCurrentState);
                }
                return;
            }

            foreach (StateMachineState mstate in stateList)
            {
                if (mstate.iState == iCurrentState)
                {
                    if (mstate.onUpdate != null)
                        mstate.onUpdate(time);
                    return;
                }
            }
        }

        public void Draw(GameTime time)
        {
            foreach (StateMachineState mstate in stateList)
            {
                if (mstate.iState == iCurrentState)
                {
                    if (mstate.onDraw != null)
                        mstate.onDraw(time);
                    return;
                }
            }
        }

        private void StateEnter(int state)
        {
            foreach (StateMachineState mstate in stateList)
            {
                if (mstate.iState == state)
                {
                    if (mstate.onEnter != null)
                        mstate.onEnter();
                    return;
                }
            }
        }

        private void StateLeave(int state)
        {
            foreach (StateMachineState mstate in stateList)
            {
                if (mstate.iState == state)
                {
                    if (mstate.onExit != null)
                        mstate.onExit();
                    return;
                }
            }
        }
    }
}
